package cn.well.cloud.quartz.core.task;

import cn.stylefeng.roses.core.util.SpringContextHolder;
import cn.stylefeng.roses.core.util.ToolUtil;
import cn.well.cloud.quartz.core.factory.QuartzJobFactory;
import cn.well.cloud.quartz.core.factory.QuartzJobFactoryDisallowConcurrentExecution;
import cn.well.cloud.quartz.core.model.ScheduleJob;
import cn.well.cloud.quartz.modular.model.TimetaskLog;
import cn.well.cloud.quartz.modular.service.ITimetaskLogService;
import cn.well.cloud.quartz.modular.service.ITimetaskService;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

@Component
public class TaskUtils {
    private final Logger log = LoggerFactory.getLogger(this.getClass());
    
    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean; //job与spring独立管理,使用spring注入job bean 需要先将bean注入到spring容器中
    
    @Autowired
    private ITimetaskLogService timetaskLogService;
    
    @Autowired
    private ITimetaskService timetaskService;

    /**
     * 通过反射调用scheduleJob中定义的方法
     * 
     * @param scheduleJob
     */
    @SuppressWarnings("unchecked")
    public void invokMethod(ScheduleJob scheduleJob) {
        Object object = null;
        Class clazz = null;
        boolean flag = true;

        TimetaskLog tlog = new TimetaskLog();
        tlog.setJobId(Long.parseLong(scheduleJob.getJobId()));
        if (ToolUtil.isNotEmpty(scheduleJob.getSpringId())) {
            object = SpringContextHolder.getBean(scheduleJob.getSpringId());
        } else if (ToolUtil.isNotEmpty(scheduleJob.getBeanClass())) {
            try {
                clazz = Class.forName(scheduleJob.getBeanClass());
                object = clazz.newInstance();
            } catch (Exception e) {
                flag = false;
                tlog.setReason("未找到" + scheduleJob.getBeanClass() + "对应的class");
                tlog.setState("fail");
            }
        }
        if (object == null) {
            flag = false;
            log.error("任务名称 = [" + scheduleJob.getJobName() + "]---------------未启动成功，请检查是否配置正确！！！");
            tlog.setReason("未找到" + scheduleJob.getBeanClass() + "对应的class");
            tlog.setState("fail");
            return;
        }
        clazz = object.getClass();
        Method method = null;
        try {
            method = clazz.getDeclaredMethod(scheduleJob.getMethodName(), new Class[] { String.class });
        } catch (NoSuchMethodException e) {
            flag = false;
            log.error("任务名称 = [" + scheduleJob.getJobName() + "]---------------未启动成功，方法名设置错误！！！/参数错误");
            tlog.setReason("未找到" + scheduleJob.getBeanClass() + "类下" + scheduleJob.getMethodName() + "对应的方法");
            tlog.setState("fail");
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        if (method != null) {
            try {
                method.invoke(object, scheduleJob.getJobData());
            } catch (IllegalAccessException e) {
                flag = false;
                tlog.setReason("未找到" + scheduleJob.getBeanClass() + "类下" + scheduleJob.getMethodName() + "对应的方法参数设置错误");
                tlog.setState("fail");
            } catch (IllegalArgumentException e) {
                flag = false;
                tlog.setReason("未找到" + scheduleJob.getBeanClass() + "类下" + scheduleJob.getMethodName() + "对应的方法参数设置错误");
                tlog.setState("fail");
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                flag = false;
                tlog.setReason("未找到" + scheduleJob.getBeanClass() + "类下" + scheduleJob.getMethodName() + "对应的方法参数设置错误");
                tlog.setState("fail");
                e.printStackTrace();
            }
        }
        if (flag) {
            System.out.println("任务名称 = [" + scheduleJob.getJobName() + "]----------启动成功");
            tlog.setState("success");
        }
        timetaskLogService.save(tlog);
    }
    
    /**
     * 添加任务
     * 
     * @param job
     * @throws SchedulerException
     */
    public void addJob(ScheduleJob job) throws SchedulerException {
      if (job == null || !ScheduleJob.STATUS_RUNNING.equals(job.getJobStatus())) {
        return;
      }

      Scheduler scheduler = schedulerFactoryBean.getScheduler();
      TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
      CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
      // 不存在，创建一个
      if (null == trigger) {
        Class clazz = ScheduleJob.CONCURRENT_IS.equals(job.getIsConcurrent()) ? QuartzJobFactory.class
                                                                             : QuartzJobFactoryDisallowConcurrentExecution.class;

        JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).usingJobData("data", job.getJobData()).build();
        jobDetail.getJobDataMap().put("scheduleJob", job);
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        trigger = TriggerBuilder.newTrigger().withDescription(job.getJobId().toString()).withIdentity(job.getJobName(), job.getJobGroup())
            .withSchedule(scheduleBuilder).build();
        scheduler.scheduleJob(jobDetail, trigger);
      } else {
        // Trigger已存在，那么更新相应的定时设置
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        // 按新的cronExpression表达式重新构建trigger
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).usingJobData("data", job.getJobData()).withSchedule(scheduleBuilder).build();
        // 按新的trigger重新设置job执行
        scheduler.rescheduleJob(triggerKey, trigger);
      }
    }
}
